// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#include <pollux/common/base/status.h>

#include <turbo/log/logging.h>
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <sstream>

namespace kumo::pollux {
    std::string_view toString(StatusCode code) {
        switch (code) {
            case StatusCode::kOK:
                return "OK";
            case StatusCode::kUserError:
                return "User error";
            case StatusCode::kTypeError:
                return "Type error";
            case StatusCode::kIndexError:
                return "Index error";
            case StatusCode::kKeyError:
                return "Key error";
            case StatusCode::kAlreadyExists:
                return "Already exists";
            case StatusCode::kOutOfMemory:
                return "Out of memory";
            case StatusCode::kIOError:
                return "IOError";
            case StatusCode::kCancelled:
                return "Cancelled";
            case StatusCode::kInvalid:
                return "Invalid";
            case StatusCode::kUnknownError:
                return "Unknown error";
            case StatusCode::kNotImplemented:
                return "NotImplemented";
        }
        return ""; // no-op
    }

    Status::Status(StatusCode code) {
        state_ = new State;
        state_->code = code;
    }

    Status::Status(StatusCode code, std::string msg) {
        if (MELON_UNLIKELY(code == StatusCode::kOK)) {
            throw std::invalid_argument("Cannot construct ok status with message");
        }
        state_ = new State;
        state_->code = code;
        state_->msg = std::move(msg);
    }

    void Status::copyFrom(const Status &s) {
        delete state_;
        if (s.state_ == nullptr) {
            state_ = nullptr;
        } else {
            state_ = new State(*s.state_);
        }
    }

    std::string_view Status::codeAsString() const {
        if (state_ == nullptr) {
            return "OK";
        }
        return ::kumo::pollux::toString(code());
    }

    std::string Status::toString() const {
        std::string result(codeAsString());
        if (state_ == nullptr) {
            return result;
        }
        result += ": ";
        result += state_->msg;
        return result;
    }

    void Status::abort() const {
        abort("");
    }

    void Status::abort(const std::string_view &message) const {
        std::cerr << "-- Pollux Fatal Error --\n";
        if (!message.empty()) {
            std::cerr << message << "\n";
        }
        std::cerr << toString() << std::endl;
        std::abort();
    }

    void Status::warn() const {
        KLOG(WARNING) << toString();
    }

    void Status::warn(const std::string_view &message) const {
        KLOG(WARNING) << message << ": " << toString();
    }
} // namespace kumo::pollux
